﻿/*************************************************************************
* Copyright(c) 2020 - Present ShenZhen EscopeTech

* ShenZhen EscopeTech Incoperated CONFIDENTIAL
* ________________________________________________________________________
*
* [2020] - Present ShenZhen EscopeTech Incoperated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of ShenZhen EscopeTech Incoperated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to ShenZhen EscopeTech Incoperated
* and its suppliers and may be covered by P.R.C. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from ShenZhen EscopeTech Incoperated.
*
*************************************************************************/

#include "DLogInfoMgr.h"

#include <QApplication>
#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QMessageLogContext>
#include <QMutex>
#include <QSettings>
#include <QStandardPaths>
#include <QTextStream>
#include <QtAlgorithms>
#include <QtDebug>
#include <iostream>

#include "DUtils.h"

namespace
{
DLogInfoMgr g_logInfoMgr;
void outputMessage(QtMsgType type, const QMessageLogContext &context,
                   const QString &msg)
{
    g_logInfoMgr.processMsg(type, context, msg);
}
}  // namespace

DLogInfoMgr *getLogInfoMgr() { return &g_logInfoMgr; }

DLogInfoMgr::DLogInfoMgr()
    : m_mutex(QMutex::Recursive)
{
}

void DLogInfoMgr::initLogInfo(const QString &strFilePath)
{
    qInstallMessageHandler(outputMessage);

    QMutexLocker locker(&m_mutex);

    QDir dirLog(QApplication::applicationDirPath());
    m_strFilePath = dirLog.path() + strFilePath;
    DUtils::makeDir(m_strFilePath);

    deleteFile(m_strFilePath, m_nMaxCountLogFile - 1);

    m_strFileName = genLogFile();
}

void DLogInfoMgr::processMsg(QtMsgType type, const QMessageLogContext &context,
                             const QString &strMsg)
{
    bool bUnknown = (context.function == nullptr || context.file == nullptr);

    QMutexLocker locker(&m_mutex);

    constexpr qint64 M = 5 * 1024 * 1024;
    qint64 fileSize = QFileInfo(m_strFileName).size();

    if (fileSize > M)
    {
        m_nLogNum++;
        if (m_nLogNum >= 1000)
        {
            m_nLogNum = 0;
        }
        // gen new file path
        m_strFileName = genLogFile();
        // clear log and corefile
        deleteFile(m_strFilePath, m_nMaxCountLogFile - 1);
    }

    bool bWriteLogFile = true;
    QString strOutMsgType;
    if (type == QtDebugMsg)
    {
        strOutMsgType = "QDebug";
        bWriteLogFile = false;
    }
    else if (type == QtInfoMsg)
    {
        strOutMsgType = "QInfo";
    }
    else if (type == QtWarningMsg)
    {
        strOutMsgType = "QWarning";
    }
    else if (type == QtCriticalMsg)
    {
        strOutMsgType = "QCriticalMsg";
    }
    else if (type == QtFatalMsg)
    {
        strOutMsgType = "QFatalMsg";
    }
    else
    {
        strOutMsgType = "QOther";
    }

    // for custom LogFormat
    QString strMsgLog;
    QString strDate =
        QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz");
    if (!bUnknown)
    {
        const bool bCustomLogTag =
            (strlen(context.function) == 0 && strlen(context.file) != 0);
        const bool bCustomLogArgs =
            (strlen(context.function) == 0 && strlen(context.file) == 0);

        if (bCustomLogTag)
        {
            strMsgLog = QString("%1 [%2] %3")
                            .arg(strDate)
                            .arg(strOutMsgType)
                            .arg(strMsg);
        }
        else if (bCustomLogArgs)
        {
            strMsgLog = QString("%1").arg(strMsg);
        }
        else
        {
            strMsgLog = QString("%1 [%2] %3::%4 %5(line) \r\n>%6")
                            .arg(strDate)
                            .arg(strOutMsgType)
                            .arg(context.file)
                            .arg(context.function)
                            .arg(context.line)
                            .arg(strMsg);
        }
    }
    else
    {
        strMsgLog =
            QString("%1 [%2] %3").arg(strDate).arg(strOutMsgType).arg(strMsg);
    }

    std::cout << strMsgLog.toLocal8Bit().data() << std::endl;

    if (bWriteLogFile)
    {
        QFile file(m_strFileName);
        file.open(QIODevice::WriteOnly | QIODevice::Append);
        QTextStream text_stream(&file);
        text_stream << strMsgLog << "\r\n";
        file.close();
    }
}

void DLogInfoMgr::deleteFile(const QString &strDir, const int &nCount)
{
    QDir dir(strDir);
    dir.setFilter(QDir::Files);

    QList<QFileInfo> fileInfoList = dir.entryInfoList();

    if (fileInfoList.size() > nCount)
    {
        std::sort(fileInfoList.begin(), fileInfoList.end(),
                  [](const QFileInfo &a, const QFileInfo &b)
                  { return a.lastModified() > b.lastModified(); });

        for (int i = nCount; i < fileInfoList.size(); i++)
        {
            dir.remove(fileInfoList.at(i).fileName());
        }
    }
}

QString DLogInfoMgr::genLogFile()
{
    // QString("%1_0.log").arg();
    QString strRet = QString("%1/%2_%3.log")
                         .arg(m_strFilePath)
                         .arg(m_dtAppStart.toString("yyyyMMdd-hhmmss"))
                         .arg(m_nLogNum, 3, 10, QChar('0'));
    return strRet;
}
